1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 Change History (most recent first):
19 $Log: Mac\040OS\040Test\040Searcher.c,v $
20 Revision 1.24 2008/11/04 19:43:35 cheshire
21 Updated comment about MAX_ESCAPED_DOMAIN_NAME size (should be 1009, not 1005)
23 Revision 1.23 2007/07/27 19:30:40 cheshire
24 Changed mDNSQuestionCallback parameter from mDNSBool to QC_result,
25 to properly reflect tri-state nature of the possible responses
27 Revision 1.22 2006/08/14 23:24:29 cheshire
28 Re-licensed mDNSResponder daemon source code under Apache License, Version 2.0
30 Revision 1.21 2004/12/16 20:49:34 cheshire
31 <rdar://problem/3324626> Cache memory management improvements
33 Revision 1.20 2004/10/19 21:33:18 cheshire
34 <rdar://problem/3844991> Cannot resolve non-local registrations using the mach API
35 Added flag 'kDNSServiceFlagsForceMulticast'. Passing through an interface id for a unicast name
36 doesn't force multicast unless you set this flag to indicate explicitly that this is what you want
38 Revision 1.19 2004/09/17 01:08:50 cheshire
39 Renamed mDNSClientAPI.h to mDNSEmbeddedAPI.h
40 The name "mDNSClientAPI.h" is misleading to new developers looking at this code. The interfaces
41 declared in that file are ONLY appropriate to single-address-space embedded applications.
42 For clients on general-purpose computers, the interfaces defined in dns_sd.h should be used.
44 Revision 1.18 2004/09/16 21:59:16 cheshire
45 For consistency with zerov6Addr, rename zeroIPAddr to zerov4Addr
47 Revision 1.17 2004/06/10 04:37:27 cheshire
48 Add new parameter in mDNS_GetDomains()
50 Revision 1.16 2004/03/12 21:30:25 cheshire
51 Build a System-Context Shared Library from mDNSCore, for the benefit of developers
52 like Muse Research who want to be able to use mDNS/DNS-SD from GPL-licensed code.
54 Revision 1.15 2004/01/24 23:55:15 cheshire
55 Change to use mDNSOpaque16fromIntVal/mDNSVal16 instead of shifting and masking
57 Revision 1.14 2003/11/14 21:27:09 cheshire
58 <rdar://problem/3484766>: Security: Crashing bug in mDNSResponder
59 Fix code that should use buffer size MAX_ESCAPED_DOMAIN_NAME (1009) instead of 256-byte buffers.
61 Revision 1.13 2003/08/14 02:19:54 cheshire
62 <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord
64 Revision 1.12 2003/08/12 19:56:24 cheshire
69 #include <stdio.h> // For printf()
70 #include <Events.h> // For WaitNextEvent()
71 #include <SIOUX.h> // For SIOUXHandleOneEvent()
73 #include "mDNSEmbeddedAPI.h" // Defines the interface to the client layer above
74 #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform
78 OTLIFO serviceinfolist
;
79 Boolean headerPrinted
;
83 typedef struct { ServiceInfo i
; mDNSBool add
; mDNSBool dom
; OTLink link
; } linkedServiceInfo
;
85 // These don't have to be globals, but their memory does need to remain valid for as
86 // long as the search is going on. They are declared as globals here for simplicity.
87 #define RR_CACHE_SIZE 1000
88 static CacheEntity rrcachestorage
[RR_CACHE_SIZE
];
89 static mDNS mDNSStorage
;
90 static mDNS_PlatformSupport PlatformSupportStorage
;
91 static SearcherServices services
;
92 static DNSQuestion browsequestion
, domainquestion
;
94 // PrintServiceInfo prints the service information to standard out
95 // A real application might want to do something else with the information
96 static void PrintServiceInfo(SearcherServices
*services
)
98 OTLink
*link
= OTReverseList(OTLIFOStealList(&services
->serviceinfolist
));
102 linkedServiceInfo
*ls
= OTGetLinkObject(link
, linkedServiceInfo
, link
);
103 ServiceInfo
*s
= &ls
->i
;
105 if (!services
->headerPrinted
)
107 printf("%-55s Type Domain IP Address Port Info\n", "Name");
108 services
->headerPrinted
= true;
113 char c_dom
[MAX_ESCAPED_DOMAIN_NAME
];
114 ConvertDomainNameToCString(&s
->name
, c_dom
);
115 if (ls
->add
) printf("%-55s available for browsing\n", c_dom
);
116 else printf("%-55s no longer available for browsing\n", c_dom
);
121 domainname type
, domain
;
122 char c_name
[MAX_DOMAIN_LABEL
+1], c_type
[MAX_ESCAPED_DOMAIN_NAME
], c_dom
[MAX_ESCAPED_DOMAIN_NAME
], c_ip
[20];
123 DeconstructServiceName(&s
->name
, &name
, &type
, &domain
);
124 ConvertDomainLabelToCString_unescaped(&name
, c_name
);
125 ConvertDomainNameToCString(&type
, c_type
);
126 ConvertDomainNameToCString(&domain
, c_dom
);
127 sprintf(c_ip
, "%d.%d.%d.%d", s
->ip
.ip
.v4
.b
[0], s
->ip
.ip
.v4
.b
[1], s
->ip
.ip
.v4
.b
[2], s
->ip
.ip
.v4
.b
[3]);
129 printf("%-55s %-16s %-14s ", c_name
, c_type
, c_dom
);
130 if (ls
->add
) printf("%-15s %5d %#s\n", c_ip
, mDNSVal16(s
->port
), s
->TXTinfo
);
131 else printf("Removed\n");
139 // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo()
140 // enqueues a record for PrintServiceInfo() to print.
141 // Note, a browsing application would *not* normally need to get all this information --
142 // all it needs is the name, to display to the user.
143 // Finding out the address, port, and txtinfo should be deferred to the time that the user
144 // actually needs to contact the service to use it.
145 static void FoundInstanceInfo(mDNS
*const m
, ServiceInfoQuery
*query
)
147 SearcherServices
*services
= (SearcherServices
*)query
->ServiceInfoQueryContext
;
148 linkedServiceInfo
*info
= (linkedServiceInfo
*)(query
->info
);
149 if (query
->info
->ip
.type
== mDNSAddrType_IPv4
)
151 mDNS_StopResolveService(m
, query
); // For this test code, one answer is sufficient
152 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
157 // When a new named instance of a service is found, FoundInstance() is called.
158 // In this sample code we turn around and immediately issue a query to resolve that service name to
159 // find its address, port, and txtinfo, but a normal browing application would just display the name.
160 static void FoundInstance(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
162 #pragma unused (question)
163 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
164 linkedServiceInfo
*info
;
166 debugf("FoundInstance %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
168 if (answer
->rrtype
!= kDNSType_PTR
) return;
169 if (!services
) { debugf("FoundInstance: services is NULL"); return; }
171 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
172 if (!info
) { services
->lostRecords
= true; return; }
174 info
->i
.name
= answer
->rdata
->u
.name
;
175 info
->i
.InterfaceID
= answer
->InterfaceID
;
176 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
177 info
->i
.ip
.ip
.v4
= zerov4Addr
;
178 info
->i
.port
= zeroIPPort
;
179 info
->add
= AddRecord
;
180 info
->dom
= mDNSfalse
;
182 if (!AddRecord
) // If TTL == 0 we're deleting a service,
183 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
184 else // else we're adding a new service
186 ServiceInfoQuery
*q
= (ServiceInfoQuery
*)OTAllocMem(sizeof(ServiceInfoQuery
));
187 if (!q
) { OTFreeMem(info
); services
->lostRecords
= true; return; }
188 mDNS_StartResolveService(m
, q
, &info
->i
, FoundInstanceInfo
, services
);
192 static void FoundDomain(mDNS
*const m
, DNSQuestion
*question
, const ResourceRecord
*const answer
, QC_result AddRecord
)
195 #pragma unused (question)
196 SearcherServices
*services
= (SearcherServices
*)question
->QuestionContext
;
197 linkedServiceInfo
*info
;
199 debugf("FoundDomain %##s PTR %##s", answer
->name
->c
, answer
->rdata
->u
.name
.c
);
201 if (answer
->rrtype
!= kDNSType_PTR
) return;
202 if (!services
) { debugf("FoundDomain: services is NULL"); return; }
204 info
= (linkedServiceInfo
*)OTAllocMem(sizeof(linkedServiceInfo
));
205 if (!info
) { services
->lostRecords
= true; return; }
207 info
->i
.name
= answer
->rdata
->u
.name
;
208 info
->i
.InterfaceID
= answer
->InterfaceID
;
209 info
->i
.ip
.type
= mDNSAddrType_IPv4
;
210 info
->i
.ip
.ip
.v4
= zerov4Addr
;
211 info
->i
.port
= zeroIPPort
;
212 info
->add
= AddRecord
;
213 info
->dom
= mDNStrue
;
215 OTLIFOEnqueue(&services
->serviceinfolist
, &info
->link
);
218 // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS
219 static Boolean
YieldSomeTime(UInt32 milliseconds
)
221 extern Boolean SIOUXQuitting
;
223 WaitNextEvent(everyEvent
, &e
, milliseconds
/ 17, NULL
);
224 SIOUXHandleOneEvent(&e
);
225 return(SIOUXQuitting
);
231 Boolean DoneSetup
= false;
234 SIOUXSettings
.asktosaveonclose
= false;
235 SIOUXSettings
.userwindowtitle
= "\pMulticast DNS Searcher";
236 SIOUXSettings
.rows
= 40;
237 SIOUXSettings
.columns
= 132;
239 printf("Multicast DNS Searcher\n\n");
240 printf("This software reports errors using MacsBug breaks,\n");
241 printf("so if you don't have MacsBug installed your Mac may crash.\n\n");
242 printf("******************************************************************************\n");
244 err
= InitOpenTransport();
245 if (err
) { debugf("InitOpenTransport failed %d", err
); return(err
); }
247 err
= mDNS_Init(&mDNSStorage
, &PlatformSupportStorage
, rrcachestorage
, RR_CACHE_SIZE
,
248 mDNS_Init_DontAdvertiseLocalAddresses
, mDNS_Init_NoInitCallback
, mDNS_Init_NoInitCallbackContext
);
249 if (err
) return(err
);
251 // Make sure OT has a large enough memory pool for us to draw from at OTNotifier (interrupt) time
252 tempmem
= OTAllocMem(0x10000);
253 if (tempmem
) OTFreeMem(tempmem
);
254 else printf("**** Warning: OTAllocMem couldn't pre-allocate 64K for us.\n");
256 services
.serviceinfolist
.fHead
= NULL
;
257 services
.headerPrinted
= false;
258 services
.lostRecords
= false;
260 while (!YieldSomeTime(35))
262 #if MDNS_ONLYSYSTEMTASK
263 // For debugging, use "#define MDNS_ONLYSYSTEMTASK 1" and call mDNSPlatformIdle() periodically.
264 // For shipping code, don't define MDNS_ONLYSYSTEMTASK, and you don't need to call mDNSPlatformIdle()
265 extern void mDNSPlatformIdle(mDNS
*const m
);
266 mDNSPlatformIdle(&mDNSStorage
); // Only needed for debugging version
268 if (mDNSStorage
.mDNSPlatformStatus
== mStatus_NoError
&& !DoneSetup
)
270 domainname srvtype
, srvdom
;
272 printf("\nSending mDNS service lookup queries and waiting for responses...\n\n");
273 MakeDomainNameFromDNSNameString(&srvtype
, "_http._tcp.");
274 MakeDomainNameFromDNSNameString(&srvdom
, "local.");
275 err
= mDNS_StartBrowse(&mDNSStorage
, &browsequestion
, &srvtype
, &srvdom
, mDNSInterface_Any
, mDNSfalse
, FoundInstance
, &services
);
277 err
= mDNS_GetDomains(&mDNSStorage
, &domainquestion
, mDNS_DomainTypeBrowse
, NULL
, mDNSInterface_Any
, FoundDomain
, &services
);
281 if (services
.serviceinfolist
.fHead
)
282 PrintServiceInfo(&services
);
284 if (services
.lostRecords
)
286 services
.lostRecords
= false;
287 printf("**** Warning: Out of memory: Records have been missed.\n");
291 mDNS_StopBrowse(&mDNSStorage
, &browsequestion
);
292 mDNS_Close(&mDNSStorage
);